package com.smsc.headend.task.engine.service.push.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.smsc.headend.common.utils.CosemUtils;
import com.smsc.headend.module.protocol.cosem.bo.CosemData;
import com.smsc.headend.module.protocol.cosem.util.CosemXmlUtils;
import com.smsc.headend.module.push.entity.ConfigNotifyType;
import com.smsc.headend.task.engine.po.DeviceDetail;
import com.smsc.headend.task.engine.registry.PushDataDecodeRegistry;
import com.smsc.headend.task.engine.service.CosemXmlService;
import com.smsc.headend.task.engine.service.FeignAssetManagementService;
import com.smsc.headend.task.engine.service.push.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * (业务实现)
 *
 * @author wjh
 * @date 2022/6/16 10:08.
 */
@Service
@Slf4j
public class DataNotifyServiceImpl implements DataNotifyService {

    @Autowired
    ConfigNotifyTypeService typeService;
    @Autowired
    PushDataDecodeRegistry pushDataDecodeRegistry;
    @Autowired
    ConfigNotifyTypeParamService paramService;
    @Autowired
    FeignAssetManagementService assetManagementService;
    @Autowired
    CosemXmlService cosemXmlService;

    @Override
    public int receiveNotificationData(Long deviceType, DeviceDetail deviceDetail, String data) {
        Long modelId = deviceDetail.getDeviceTypeGroup().getModelId();
        CosemData cosemData = CosemXmlUtils.translateCosemXml(data);
        if (null == cosemData) {
            log.info("Device Notification: cosemData is null");
            return 1;
        }
        log.info("Device Notification: cosemData={}", JSONUtil.toJsonStr(cosemData));
        Long dataItemId = null;
        CosemData notifyData = cosemData;
        if ("GatewayRequest".equals(notifyData.getType()) || "GatewayResponse".equals(notifyData.getType())) {
            notifyData = notifyData.getChildAt(2);
        }
        if (null == notifyData) {
            log.info("Device Notification: cosemData child at 2 is null");
            return 1;
        }
        String serviceType = notifyData.getType();
        Integer serviceTypeCode = ConfigNotifyType.getServiceCodeByType(serviceType);
        if (null == serviceTypeCode) {
            log.info("Device Notification: serviceType not support");
            return 1;
        }
        //type = DataNotification,  dataValue index is 2,0
        CosemData dateData = null;
        Date uploadDate = null;
        if ("DataNotification".equals(notifyData.getType())) {
            dateData = notifyData.getChildAt(1);
            if (null != dateData && "DateTime".equals(dateData.getType())) {
                //巴西POC上报的掉电上电事件中，时间为全F，需要过滤掉
                if (!"FFFFFFFFFFFFFFFFFFFFFFFF".equalsIgnoreCase(dateData.getValue())) {
                    uploadDate = (Date) cosemXmlService.getData(dateData.getType(), dateData.getValue());
                }
            }
            notifyData = notifyData.getChildAt(2);
            if (null == notifyData) {
                log.info("Device Notification: notifyData child at 2 is null");
                return 1;
            }
            notifyData = notifyData.getChildAt(0);
        }

        List<ConfigNotifyType> notifyTypes = typeService.getListByModelIdAndServiceType(modelId, serviceTypeCode);
        //找不到设备型号与通知类型的映射信息，直接中断流程
        if (CollectionUtils.isEmpty(notifyTypes)) {
            log.info("receiveNotificationData configNotifyType list is empty,modelId:{},serviceType:{}", modelId, serviceType);
            return 1;
        }
        ConfigNotifyType configNotifyType = getOnlyConfigNotifyType(notifyTypes, notifyData);
        if (null == configNotifyType) {
            //未找到配置
            log.warn("receiveNotificationData no ConfigNotifyType,modelId:{}", modelId);
            return 1;
        }
        if (StrUtil.isNotEmpty(configNotifyType.getObisValue())) {
            dataItemId = assetManagementService.getDateItemIdByObisAndModelId(modelId, configNotifyType.getObisValue());
        } else {
            dataItemId = -1L;
        }
        PushDataDecodeHandler handler = pushDataDecodeRegistry.getService(configNotifyType.getMessageType());
        handler.handler(notifyData, configNotifyType, deviceDetail, dataItemId, uploadDate);
        return 0;
    }


    private ConfigNotifyType getOnlyConfigNotifyType(List<ConfigNotifyType> notifyTypes, CosemData cosemData) {
        if (notifyTypes.size() == 1) {
            ConfigNotifyType configNotifyType = notifyTypes.get(0);
            //只有一个ConfigNotifyType且无obis配置，取该配置
            if (StrUtil.isEmpty(configNotifyType.getObisIndex())) {
                return configNotifyType;
            }
            String obis = getObisByIndex(cosemData, configNotifyType.getObisIndex());
            obis = CosemUtils.octObisToDotFormat(obis);
            if (null != obis && obis.equals(configNotifyType.getObisValue())) {
                //只有一个ConfigNotifyType且可根据obis配置解析出obis，取该配置
                return configNotifyType;
            } else {
                //只有一个ConfigNotifyType且不可根据obis配置解析出obis，认为没有配置
                return null;
            }
        }

        Map<String, List<ConfigNotifyType>> notifyTypesMap;
        List<ConfigNotifyType> notifyTypesForObisIndexIsNull = notifyTypes
                .stream()
                .filter(e -> StrUtil.isEmpty(e.getObisIndex()))
                .collect(Collectors.toList());
        notifyTypesMap = notifyTypes.stream()
                .filter(e -> StrUtil.isNotEmpty(e.getObisIndex()))
                .collect(Collectors.groupingBy(ConfigNotifyType::getObisIndex));
        //多个ConfigNotifyType且均无obis配置，认为没有配置
        if (notifyTypesMap.isEmpty()) {
            return null;
        }
        String obis = null;
        List<ConfigNotifyType> activeNotifyTypeList = new ArrayList<>();
        for (String obisIndex : notifyTypesMap.keySet()) {
            obis = getObisByIndex(cosemData, obisIndex);
            if (null != obis) {
                activeNotifyTypeList = notifyTypesMap.get(obisIndex);
                break;
            }
        }
        //无法解析出obis
        if (null == obis) {
            //只剩下一个没有配置obisIndex，取该配置
            if (1 == notifyTypesForObisIndexIsNull.size()) {
                return notifyTypesForObisIndexIsNull.get(0);
            }
            return null;
        }
        obis = CosemUtils.octObisToDotFormat(obis);
        //只有一个ConfigNotifyType可以解析出obis
        if (activeNotifyTypeList.size() == 1) {
            if (obis.equals(activeNotifyTypeList.get(0).getObisValue())) {
                //解析出的obis与配置的obis相等，取该配置
                return activeNotifyTypeList.get(0);
            } else {
                //解析出的obis与配置的obis不相等，则没有配置
                return null;
            }
        }
        obis = CosemUtils.octObisToDotFormat(obis);
        //多个ConfigNotifyType可以解析出obis,则用解析出的obis反查，从activeNotifyTypeList获取配置
        String finalObis = obis;
        return activeNotifyTypeList.stream().filter(e -> finalObis.equals(e.getObisValue())).findFirst().orElse(null);
    }


    private String getObisByIndex(CosemData cosemData, String index) {
        CosemData obisCosemData = paramService.getCosemDataByIndex(cosemData, index);
        return null == obisCosemData ? null : obisCosemData.getValue();
    }


}
